﻿namespace FilteredPageReference
{
    using System;
    using System.Globalization;
    using System.IO;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using EPiServer;
    using EPiServer.Core;
    using EPiServer.Core.PropertySettings;
    using EPiServer.Web.PropertyControls;

    /// <summary>
    /// Property filtered page reference control
    /// </summary>
    [PropertySettings(typeof(PropertyFilteredPageReferenceSettings), true)]
    public class PropertyFilteredPageReferenceControl : PropertyPageReferenceControl
    {


        /// <summary>
        /// Applies the edit changes.
        /// </summary>
        public override void ApplyEditChanges()
        {
            if (!ValidateThatReferencedPageIsOfCorrectType(EditControl.PageLink))
            {
                string validationErrorMessage = string.Empty;
                string allowedPageTypes = string.Empty;

                if (PropertyData.SettingsContainer != null)
                {
                    PropertySettingsWrapper settingsWrapper = PropertyData.SettingsContainer.GetSetting(typeof(PropertyFilteredPageReferenceSettings));

                    if (settingsWrapper != null)
                    {
                        PropertyFilteredPageReferenceSettings settings = settingsWrapper.PropertySettings as PropertyFilteredPageReferenceSettings;

                        if (settings != null)
                        {
                            if (!string.IsNullOrEmpty(settings.ValidationErrorMessage))
                                validationErrorMessage = settings.ValidationErrorMessage;
                            else
                                allowedPageTypes = Helper.GetCommaDelimitedListOfAllowedPageTypes(settings.PageTypeNames,
                                                                                              settings.FullTypeNames);
                        }
                    }
                }

                if (!string.IsNullOrEmpty(validationErrorMessage))
                    AddErrorValidator(validationErrorMessage);
                else
                {
                    if (!string.IsNullOrEmpty(allowedPageTypes))
                    {
                        AddErrorValidator(string.Format(LanguageHelper.Translate("/filteredPageReference/selectedPageTypesWithValidPageTypesMessage"),
                            PropertyData.TranslateDisplayName(), allowedPageTypes));
                    }
                    else
                    {
                        AddErrorValidator(string.Format(LanguageHelper.Translate("/filteredPageReference/selectedPageIsNotValidMessage"),
                            PropertyData.TranslateDisplayName()));
                    }
                }
            }

            base.ApplyEditChanges();
        }

        /// <summary>
        /// Creates the edit controls.
        /// </summary>
        public override void CreateEditControls()
        {
            base.CreateEditControls();

            object value = PropertyData.Value;

            if (value != null)
                EditControl.PageLink = value as PageReference;
        }

        /// <summary>
        /// Adds the quick edit link.
        /// </summary>
        /// <param name="linkedPage">The linked page.</param>
        /// <param name="settings">The settings.</param>
        private void AddQuickEditLink(PropertyFilteredPageReferenceSettings settings)
        {
            if (!settings.AllowQuickEdit)
                return;

            object value = PropertyData.Value;
            PageReference linkedPage = PageReference.EmptyReference;

            if (value != null)
                linkedPage = value as PageReference; 

            string valueVariableName = string.Concat("fprQuickEditing_", Name);
            string containerId = valueVariableName + "Container";

            const string script = @"<script type=""text/javascript"">
                                    {2} = '{3}';
                                    function fprQuickEditing_{4}_Changed() 
                                    {{ 
                                        var value = $('#{0}').val();
                                    
                                        if (value != '')
                                        {{
                                            $('#{1}').show(); 
                                            {2} = value;
                                        }}
                                        else
                                        {{
                                            $('#{1}').hide(); 
                                            {2} = '';
                                        }}
                                    }};
                                 </script>";

            Literal literal = new Literal { Text = string.Format("<div id=\"{0}\"{1}>", containerId, PageReference.IsNullOrEmpty(linkedPage) ? " style=\"display:none\"" : string.Empty) };
            Controls.Add(literal);

            literal = new Literal 
            { 
                Text = string.Format(script, 
                    EditControl.ValueControl.ClientID, 
                    containerId, 
                    valueVariableName,
                    PageReference.IsNullOrEmpty(linkedPage) ? string.Empty : linkedPage.ToString(),
                    Name)
            };
            Controls.Add(literal);

            var quickEditLink = new HyperLink();
            string editLink =
                string.Format(
                CultureInfo.InvariantCulture,
                "javascript:window.open('{0}EditPanel.aspx?id=' + {1} + '&mode=simpleeditmode','fprquickeditwindow','width={2},height={3}');",
                              UriSupport.ResolveUrlFromUIAsRelativeOrAbsolute("edit/"),
                              valueVariableName,
                              settings.PopupWidth, 
                              settings.PopupHeight);

            quickEditLink.Attributes["onclick"] = editLink;
            quickEditLink.NavigateUrl = "javascript:void(0);";
            quickEditLink.Text = LanguageHelper.Translate("/filteredPageReference/quickEditLinkText");
            Controls.Add(quickEditLink);

            literal = new Literal { Text = "</div>" };
            Controls.Add(literal);
        }

        /// <summary>
        /// Renders the control to the specified HTML writer.
        /// </summary>
        /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the control content.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            PropertyFilteredPageReferenceSettings settings = GetSettings();
            AddQuickEditLink(settings);

            StringBuilder stringBuilder = new StringBuilder();
            using (StringWriter stringWriter = new StringWriter(stringBuilder))
            {
                using (HtmlTextWriter htmlTextWriter = new HtmlTextWriter(stringWriter))
                {
                    base.Render(htmlTextWriter);
                }
            }

            string html = stringBuilder.ToString();
            string sessionKey = string.Empty;

            if (PropertyData.PageDefinitionID == 0)
            {
                sessionKey = Guid.NewGuid().ToString("N") + "_" + PropertyData.Name;
                HttpContext.Current.Session[sessionKey] = settings;
            }
            
            string pageBrowserUrl = UriSupport.ResolveUrlFromUIBySettings("edit/pagebrowser.aspx");
            int index = html.ToLower().IndexOf(pageBrowserUrl.ToLower());

            if (index != -1)
            {
                html = html.Remove(index, pageBrowserUrl.Length);
                html = html.Insert(index, "/util/FilteredPageReference/PageBrowserFilteredPageReference.aspx?fprkey=" + sessionKey + "&fprdata=" +
                                                        HttpUtility.UrlEncode(string.Format("{0}|{1}|{2}|{3}|{4}|{5}&id=",
                                                                                            CurrentPage.PageLink.ID,
                                                                                            CurrentPage.PageLink.WorkID,
                                                                                            CurrentPage.LanguageBranch,
                                                                                            CurrentPage.PageTypeID,
                                                                                            CurrentPage.ParentLink.ID,
                                                                                            PropertyData.Name)));
            }

            writer.Write(html);
        }

        /// <summary>
        /// Validates the type of the that referenced page is of correct.
        /// </summary>
        /// <param name="pageReference">The page reference.</param>
        /// <returns>True if valid page, otherwise false</returns>
        private bool ValidateThatReferencedPageIsOfCorrectType(PageReference pageReference)
        {
            PropertyInformation propertyInformation = new PropertyInformation
                                                          {
                                                              LanguageId = CurrentPage.LanguageBranch,
                                                              PageId = CurrentPage.PageLink.ID.ToString(),
                                                              PageTypeId = CurrentPage.PageTypeID,
                                                              ParentPageId = CurrentPage.ParentLink.ID.ToString(),
                                                              PropertyName = PropertyData.Name,
                                                              WorkId = CurrentPage.PageLink.WorkID
                                                          };

            return PageReference.IsNullOrEmpty(pageReference) || Helper.IsValidPage(pageReference, PropertyData.SettingsContainer, propertyInformation);
        }

        /// <summary>
        /// Gets the properrty settings.
        /// </summary>
        /// <returns></returns>
        private PropertyFilteredPageReferenceSettings GetSettings()
        {
            PropertyFilteredPageReferenceSettings settings = null;

            if (PropertyData.SettingsContainer != null)
            {
                PropertySettingsWrapper settingsWrapper = PropertyData.SettingsContainer.GetSetting(typeof(PropertyFilteredPageReferenceSettings));

                if (settingsWrapper != null)
                    settings = settingsWrapper.PropertySettings as PropertyFilteredPageReferenceSettings;
            }

            if (settings == null)
                settings = new PropertyFilteredPageReferenceSettings();

            return settings;
        }
    }
}